#include "GThread.h"
#include "GBusyWait.h"
#include "GSpinMutex.h"
#include "GTypes.h"
#include "GError.h"

#include <Windows.h>

namespace GThread
{
	void GSpinMutex::InternalFree(GUInt32 ThreadId)
	{
		GUInt32 Expected = ThreadId;

		bool Result = Owner.compare_exchange_strong(Expected, 0, std::memory_order_release, std::memory_order_acquire);

		GUtil::GError::DebugCheck(!Result && (Expected != ThreadId), "Trying to free a mutex that that is not owned.");
	}

	bool GSpinMutex::InternalAcquire(GUInt32 ThreadId)
	{
		GUInt32 Expected = 0;

		return Owner.compare_exchange_weak(Expected, ThreadId, std::memory_order_release, std::memory_order_relaxed);
	}

	GSpinMutex::GSpinMutex()
	{
		Owner.store(0, std::memory_order_release);
	}

	GSpinMutex::~GSpinMutex()
	{
		GUInt32 Value = Owner.load(std::memory_order_acquire);
		GUtil::GError::DebugCheck(Value != 0, "Mutex being destroyed before freed.");
	}

	void GSpinMutex::Free()
	{
		GUInt32 ThreadId = GThread::GetCurrentThreadId();

		InternalFree(ThreadId);
	}

	void GSpinMutex::Acquire()
	{
		GUInt32 ThreadId = GThread::GetCurrentThreadId();

		GBusyWait BusyWait;
		while (!InternalAcquire(ThreadId))
		{
			BusyWait.Wait();
		}
	}

	bool GSpinMutex::TryAcquire()
	{
		GUInt32 ThreadId = GThread::GetCurrentThreadId();
		return InternalAcquire(ThreadId);
	}
	
	bool GSpinMutex::IsLocked()
	{
		return Owner.load(std::memory_order_acquire) != 0;
	}

	GSpinMutex::GSpinMutex(const GSpinMutex& Other)
	{
	}

	GSpinMutex& GSpinMutex::operator=(const GSpinMutex& Other)
	{
		return *this;
	}
}